
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGraphics.h"
#include "SkRandom.h"
#include "SkFlipPixelRef.h"
#include "SkPageFlipper.h"

#include <pthread.h>

#define WIDTH   160
#define HEIGHT  200

static bool gDone;

static void bounce(SkScalar* x, SkScalar* dx, const int max)
    {
    *x += *dx;
    if (*x < 0)
        {
        *x = 0;
        if (*dx < 0)
            {
            *dx = -*dx;
            }
        }
    else if (*x > SkIntToScalar(max))
        {
        *x = SkIntToScalar(max);
        if (*dx > 0)
            {
            *dx = -*dx;
            }
        }
    }

static void* draw_proc(void* context)
    {
    const int OVALW = 32;
    const int OVALH = 32;

    const SkBitmap* bm = static_cast<const SkBitmap*>(context);
    SkFlipPixelRef* ref = static_cast<SkFlipPixelRef*>(bm->pixelRef());

    const int DSCALE = 1;
    SkScalar    dx = SkIntToScalar(7) / DSCALE;
    SkScalar    dy = SkIntToScalar(5) / DSCALE;
    SkScalar    x = 0;
    SkScalar    y = 0;

    SkPaint paint;

    paint.setAntiAlias(true);
    paint.setColor(SK_ColorRED);

    SkRect oval;
    oval.setEmpty();

    SkRect clipR = SkRect::MakeWH(SkIntToScalar(bm->width()), SkIntToScalar(bm->height()));
    clipR.inset(SK_Scalar1/4, SK_Scalar1/4);

    while (!gDone)
        {
        ref->inval(oval, true);
        oval.set(x, y, x + SkIntToScalar(OVALW), y + SkIntToScalar(OVALH));
        ref->inval(oval, true);

        SkAutoFlipUpdate    update(ref);

        if (!update.dirty().isEmpty())
            {
            // this must be local to the loop, since it needs to forget the pixels
            // its writing to after each iteration, since we do the swap
            SkCanvas    canvas(update.bitmap());
            canvas.clipRegion(update.dirty());
            canvas.drawColor(0, SkXfermode::kClear_Mode);
            canvas.clipRect(clipR, SkRegion::kIntersect_Op, true);

            canvas.drawOval(oval, paint);
            }
        bounce(&x, &dx, WIDTH-OVALW);
        bounce(&y, &dy, HEIGHT-OVALH);
        }
    return NULL;
    }

static const SkBitmap::Config gConfigs[] =
    {
    SkBitmap::kARGB_8888_Config,
    SkBitmap::kRGB_565_Config,
    SkBitmap::kARGB_4444_Config,
    SkBitmap::kA8_Config
    };

class PageFlipView : public SampleView
    {
    public:

        enum { N = SK_ARRAY_COUNT(gConfigs) };

        pthread_t   fThreads[N];
        SkBitmap    fBitmaps[N];

        PageFlipView()
            {
            gDone = false;
            for (int i = 0; i < N; i++)
                {
                int             status;
                pthread_attr_t  attr;

                status = pthread_attr_init(&attr);
                SkASSERT(0 == status);

                fBitmaps[i].setConfig(gConfigs[i], WIDTH, HEIGHT);
                SkFlipPixelRef* pr = new SkFlipPixelRef(gConfigs[i], WIDTH, HEIGHT);
                fBitmaps[i].setPixelRef(pr)->unref();
                fBitmaps[i].eraseColor(0);

                status = pthread_create(&fThreads[i], &attr,  draw_proc, &fBitmaps[i]);
                SkASSERT(0 == status);
                }
            this->setBGColor(0xFFDDDDDD);
            }

        virtual ~PageFlipView()
            {
            gDone = true;
            for (int i = 0; i < N; i++)
                {
                void* ret;
                int status = pthread_join(fThreads[i], &ret);
                SkASSERT(0 == status);
                }
            }

    protected:
        // overrides from SkEventSink
        virtual bool onQuery(SkEvent* evt)
            {
            if (SampleCode::TitleQ(*evt))
                {
                SampleCode::TitleR(evt, "PageFlip");
                return true;
                }
            return this->INHERITED::onQuery(evt);
            }

        virtual void onDrawContent(SkCanvas* canvas)
            {
            SkScalar x = SkIntToScalar(10);
            SkScalar y = SkIntToScalar(10);
            for (int i = 0; i < N; i++)
                {
                canvas->drawBitmap(fBitmaps[i], x, y);
                x += SkIntToScalar(fBitmaps[i].width() + 20);
                }
            this->inval(NULL);
            }

        virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)
            {
            this->inval(NULL);
            return this->INHERITED::onFindClickHandler(x, y);
            }

        virtual bool onClick(Click* click)
            {
            return this->INHERITED::onClick(click);
            }

    private:
        typedef SampleView INHERITED;
    };

//////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory()
    {
    return new PageFlipView;
    }
static SkViewRegister reg(MyFactory);

